﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.DirectoryServices;
using System.IO;
using System.Management.Automation.Runspaces;
using System.Management.Automation;
using System.Management;
using System.Management.Automation.Host;
using System.Xml;
using System.DirectoryServices.ActiveDirectory;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Security.Cryptography;
using System.Threading;
using System.Net;
using System.Text;
using System.Collections.ObjectModel;

namespace Main
{
    public class ControlDomains
    {
        public class Model
        {
            public class VerifiedDomainName
            {
                private String _domainName;
                private String _DNSSRV;
                private int _id;

                public VerifiedDomainName()
                {

                }
                public int Id
                {
                    get { return _id; }
                    set { _id = value; }
                }
                public String DomainName
                {
                    get { return _domainName; }
                    set { _domainName = value; }
                }
                public String DNSSRV
                {
                    get { return _DNSSRV; }
                    set { _DNSSRV = value; }
                }
            }
        }

        public class Control
        {
            ControlCommon common = new ControlCommon();

            /// <summary>
            /// saves Office365-enabled Domain Name on SQL Azure
            /// </summary>
            /// <param name="liveID"></param>
            /// <param name="livePW"></param>
            /// <returns></returns>
            public String CreateDomainName(string domainName, string companyName)
            {
                try
                {
                    common.CreateLog("Starting saving of Domain Name on SQL Azure for: " + domainName);

                    TechnoStoreMainDataContext db = new TechnoStoreMainDataContext();
                    VerifiedDomain domain = new VerifiedDomain();
                    domain.DomainName = domainName;
                    domain.Company = companyName;
                    db.VerifiedDomains.InsertOnSubmit(domain);
                    db.SubmitChanges();
                    db.Dispose();

                    common.CreateLog("Stopping Successful saving of Domain Name on SQL Azure for: " + domainName);

                    string output = CreateDomainNameOn365(domainName, companyName);

                    if (output != "false")
                        return output;
                    else
                    {
                        db.VerifiedDomains.DeleteAllOnSubmit(ViewDomainName(companyName));
                        db.SubmitChanges();
                        db.Dispose();
                        return "Domain Name has NOT been created!";
                    }
                }
                catch (Exception e)
                {
                    common.CreateLog(e.ToString());
                    return e.ToString();
                }
            }

            /// <summary>
            /// Triggers Powershell to automatically define domain name on existing Office 365 account
            /// </summary>
            /// <param name="domainName"></param>
            /// <returns>MS string need to be added as SRV record in the domains DNS server</returns>
            public String CreateDomainNameOn365(string domainName, string companyName)
            {
                try
                {
                    common.CreateLog("Starting Enabling of Domain Name on 365 for: " + domainName);

                    TechnoStoreMainDataContext db = new TechnoStoreMainDataContext();
                    var query = from u in db.WindowsLiveIDs
                                where u.WL_ID != String.Empty && u.Company == companyName
                                select new { u.WL_ID };
                    string credentialID = query.SingleOrDefault().WL_ID;

                    var query2 = from u in db.WindowsLiveIDs
                                 where u.WL_ID != String.Empty && u.Company == companyName
                                 select new { u.WL_Password };
                    string credentialPW = query2.SingleOrDefault().WL_Password;


                    string[] psScript = { @"$pass = convertto-securestring -asplaintext """ + credentialPW + @""" -force",
                                    @"$credential = new-object -typename System.Management.Automation.PSCredential -argumentlist """ + credentialID + @""", $pass",
                                    @"Import-Module MSOnline",
                                    @"Connect-MsolService -Credential $credential",
                                    @"New-MsolDomain -Name " + domainName + "",
                                    @"Get-MsolDomainVerificationDns -DomainName " + domainName + "",
                                    ""};

                    if (File.Exists(common.getPath("scriptCreateDomain.ps1")))
                        File.Delete(common.getPath("scriptCreateDomain.ps1"));
                    System.IO.File.WriteAllLines(common.getPath("scriptCreateDomain.ps1"), psScript);
                    RunspaceConfiguration rsConfig = RunspaceConfiguration.Create();
                    Runspace myRunspace = RunspaceFactory.CreateRunspace(rsConfig);
                    myRunspace.Open();
                    Command command = new Command(common.getPath("scriptCreateDomain.ps1"));
                    Pipeline pipeline = myRunspace.CreatePipeline();
                    pipeline.Commands.Add(command);
                    StringBuilder stringBuilder = new StringBuilder();
                    Collection<PSObject> results = pipeline.Invoke();
                    // check for errors (non-terminating) 
                    if (pipeline.Error.Count > 0)
                    {
                        //iterate over Error PipeLine until end 
                        while (!pipeline.Error.EndOfPipeline)
                        {
                            //read one PSObject off the pipeline 
                            var value = pipeline.Error.Read() as PSObject;
                            if (value != null)
                            {
                                //get the ErrorRecord 
                                var r = value.BaseObject as ErrorRecord;
                                if (r != null)
                                {
                                    //build whatever kind of message your want 
                                    stringBuilder.AppendLine(r.InvocationInfo.MyCommand.Name + " : " + r.Exception.Message);
                                    stringBuilder.AppendLine(r.InvocationInfo.PositionMessage);
                                    stringBuilder.AppendLine(string.Format("+ CategoryInfo: {0}", r.CategoryInfo));
                                    stringBuilder.AppendLine(
                                    string.Format("+ FullyQualifiedErrorId: {0}", r.FullyQualifiedErrorId));
                                }
                            }
                        }
                        common.CreateLog("Stopping Enabling of Domain Name on 365 for: " + domainName + " with the following ERROR: " + stringBuilder.ToString());
                        pipeline.Dispose();
                        myRunspace.Close();
                        myRunspace.Dispose();
                        rsConfig = null;
                        db.Dispose();
                        return "false";
                    } 

                    if (results.Count > 0)
                    {
                        stringBuilder = new StringBuilder();
                        foreach (PSObject obj in results)
                        {
                            foreach (PSPropertyInfo psPropertyInfo in obj.Properties)
                            {
                                //get the value to be added as a DNS SRV record to verify the domain
                                if (psPropertyInfo.Name == "Label")
                                    stringBuilder.AppendLine(psPropertyInfo.Value.ToString());
                            }
                        }
                        pipeline.Dispose();
                        myRunspace.Close();
                        myRunspace.Dispose();
                        rsConfig = null;

                        string output = stringBuilder.ToString();
                        output = output.Substring(0, 10);
                        VerifiedDomain domain = db.VerifiedDomains.Where(u => u.DomainName == domainName && u.Company == companyName).SingleOrDefault();
                        domain.DNSSRV = output;
                        db.SubmitChanges();
                        db.Dispose();
                        common.CreateLog("Stopping Successful Enabling of Domain Name on 365 for: " + domainName + "    PS output: " + output);

                        return output;
                    }
                    else
                        return "false";
                }

                catch (Exception e)
                {
                    common.CreateLog(e.ToString());
                    return "false";
                }
            }

            /// <summary>
            /// gets previosly defined Domain Names from SQL Azure if any
            /// </summary>
            /// <returns></returns>
            public List<VerifiedDomain> ViewDomainName(string companyName)
            {
                TechnoStoreMainDataContext db = new TechnoStoreMainDataContext();
                var query = from u in db.VerifiedDomains
                            orderby u.DomainName ascending
                            where u.DomainName != String.Empty && u.Company == companyName
                            select u;

                return query.ToList();
            }


            /// <summary>
            /// Triggers Powershell to automatically verify domain name created at previous step
            /// </summary>
            /// <param name="domainName"></param>
            /// <returns></returns>
            public String VerifyDomainOn365(string domainName, string companyName)
            {
                try
                {
                    common.CreateLog("Starting Verifying of Domain Name on 365 for: " + domainName);

                    TechnoStoreMainDataContext db = new TechnoStoreMainDataContext();
                    var query = from u in db.WindowsLiveIDs
                                where u.WL_ID != String.Empty && u.Company == companyName
                                select new { u.WL_ID };
                    string credentialID = query.SingleOrDefault().WL_ID;

                    var query2 = from u in db.WindowsLiveIDs
                                 where u.WL_ID != String.Empty && u.Company == companyName
                                 select new { u.WL_Password };
                    string credentialPW = query2.SingleOrDefault().WL_Password;

                    string[] psScript = { @"$pass = convertto-securestring -asplaintext """ + credentialPW + @""" -force",
                                    @"$credential = new-object -typename System.Management.Automation.PSCredential -argumentlist """ + credentialID + @""", $pass",
                                    @"Import-Module MSOnline",
                                    @"Connect-MsolService -Credential $credential",
                                    @"Confirm-MsolDomain -DomainName " + domainName + "",
                                    ""};

                    if (File.Exists(common.getPath("scriptVerifyDomain.ps1")))
                        File.Delete(common.getPath("scriptVerifyDomain.ps1"));
                    System.IO.File.WriteAllLines(common.getPath("scriptVerifyDomain.ps1"), psScript);
                    RunspaceConfiguration rsConfig = RunspaceConfiguration.Create();
                    Runspace myRunspace = RunspaceFactory.CreateRunspace(rsConfig);
                    myRunspace.Open();
                    Command command = new Command(common.getPath("scriptVerifyDomain.ps1"));
                    Pipeline pipeline = myRunspace.CreatePipeline();
                    pipeline.Commands.Add(command);
                    StringBuilder stringBuilder = new StringBuilder();
                    Collection<PSObject> results = pipeline.Invoke();
                    // check for errors (non-terminating) 
                    if (pipeline.Error.Count > 0)
                    {
                        //iterate over Error PipeLine until end 
                        while (!pipeline.Error.EndOfPipeline)
                        {
                            //read one PSObject off the pipeline 
                            var value = pipeline.Error.Read() as PSObject;
                            if (value != null)
                            {
                                //get the ErrorRecord 
                                var r = value.BaseObject as ErrorRecord;
                                if (r != null)
                                {
                                    //build whatever kind of message your want 
                                    stringBuilder.AppendLine(r.InvocationInfo.MyCommand.Name + " : " + r.Exception.Message);
                                    stringBuilder.AppendLine(r.InvocationInfo.PositionMessage);
                                    stringBuilder.AppendLine(string.Format("+ CategoryInfo: {0}", r.CategoryInfo));
                                    stringBuilder.AppendLine(
                                    string.Format("+ FullyQualifiedErrorId: {0}", r.FullyQualifiedErrorId));
                                }
                            }
                        }
                        common.CreateLog("Stopping Verifying of Domain Name on 365 for: " + domainName + " with the following ERROR: " + stringBuilder.ToString());
                        pipeline.Dispose();
                        myRunspace.Close();
                        myRunspace.Dispose();
                        rsConfig = null;
                        db.Dispose();
                        return "false";
                    } 

                    pipeline.Dispose();
                    myRunspace.Close();
                    myRunspace.Dispose();
                    rsConfig = null;
                    db.Dispose();
                    common.CreateLog("Stopping Successful Verifying of Domain Name on 365 for: " + domainName);

                    return "true";
                }
                catch (Exception e)
                {
                    common.CreateLog(e.ToString());
                    return "false";
                }
            }
        }
    }
}